來到了第九天。但一樣先講結論,如果你很急著用,可以直接使用這份 Add-On: Drive Explorer,功能還蠻強大的!自己寫的好處是,如果你想結合其他功能會比較方便。對於想知道怎麼做的人,讓我們開始吧!
現在幾乎每天都會打開 Google Drive,但有時當檔案一多,就會面臨兩個問題——權限設置不清,當一個人加入或離職時,要重複好幾次開開關關。又或是要將不同的線上文件寄信並分享給不同人,這些都會需要知道檔案 ID。有沒有一個快速的方式,可以讓我們抓出特定資料夾內的檔案 ID,並用一個表格管理權限呢?
這次的主題我們會分成兩天寫。第一題會在今天跟大家分享,明天會針對第二題與第三題。那我們就開始吧!
因為我們要用到 Google Sheet ,所以一樣用其作為開啟的管道。借用一下 D8 的影片,來說明怎麼樣開啟一個有連結 GAS 的 Google Sheet。
一樣執行時會有「需要驗證」出現,讓我借用一下 D2 的影片。
這邊我們開一個資料夾,並且在裡面設置一些檔案,其中有一些是有子目錄的。要注意裡面有個「demo」資料夾
那這邊要特別提一下「ID」的概念,每一個 Google 產品都有特定的 ID,位置可以參考這張圖
這邊提供兩種取得方式——
一種是直接從網址上複製,另一種是按右鍵時會出現的。這邊用影片解釋。好,那當我們取得要抓的檔案 ID 後,就是將其丟到 GAS 上,一樣開一個 environment.gs
存放資料。這邊示範完整的流程——
在 Google Drive 官方定義的 API 中,主要會將能操作的物件分成三種,分別是 Folder
、File
和User
。會用不同的 API 讀取。
我們來拆解步驟——
getFolderById()
讀取 Folder
。getFiles()
會讀出 files
(實際上是 fileIterator
,但可以理解成「很多檔案」就是)。files
(fileIterator
)會將這個資料夾內的檔案一個個列出來,這邊我列出它的檔名(getName()
)和 ID(getId()
)。完整程式碼在這——
function readFiles(){
let folder = DriveApp.getFolderById(drive_ID);
let files = folder.getFiles();
let file_arr = []
while (files.hasNext()) {
let file = files.next();
file_arr.push([file.getName(),file.getId()]);
};
Logger.log(file_arr);
}
跑起來長這樣——
好那你會發現一個問題,是這邊並沒有列出「資料夾」。仔細一看會發現我們裡面並沒有我們在 Step 2 埋梗的「資料夾」 demo
,那請問我們要如何抓到 demo
與裡面的小資料夾(還有資料)?
Step 3 我們是用 getFiles()
,這邊我們就帶大家來看看 getFolders()
怎麼樣讀取。
這邊我們要用到的技巧叫做 DP (Dynamic Programming),簡單來說就是(1)在根目錄(或目標位置)執行 DP,去發現子目錄,而(2)進到每個子目錄後,一旦發現還有子子目錄,就會再執行一次 DP,並且不斷重複到找到全部的位置為止。
程式碼長這樣,是直接借用 rpm 在 Stakeholder 的回應:Google apps script - iterate folder and subfolder,覺得寫得很好懂。其中的 getSubFolders(parent)
中還有 getSubFolders(child)
的寫法,就是所謂的 DP。
function getSubFolders(parent) {
parent = parent.getId();
let childFolder = DriveApp.getFolderById(parent).getFolders();
while(childFolder.hasNext()) {
let child = childFolder.next();
Logger.log(child.getName());
getSubFolders(child);
}
return;
}
function listFolders() {
let parentFolder = DriveApp.getFolderById(drive_ID);
let childFolders = parentFolder.getFolders();
while(childFolders.hasNext()) {
let child = childFolders.next();
Logger.log(child.getName());
getSubFolders(child);
}
}
好,那執行起來會長什麼樣子呢?(可以參考 Step 2 的架構圖)——
但這樣只有列出「目錄」,又要怎麼樣列出所有檔案,包括子目錄內的檔案呢?讓我們從 Step 5 來看看。
這邊就要結合我們的 Step 3 和 Step 4 啦。我們先將 Step 3 改寫成會讀取輸入的 Folder
Object 的 function。
function readFilesInFolder(folder){
let files = folder.getFiles();
while (files.hasNext()) {
let file = files.next();
Logger.log([file.getName(),file.getId()]);
};
}
接著,在將上面這段放入 Step 4 中。
function getSubFolders(parent) {
parent = parent.getId();
let childFolder = DriveApp.getFolderById(parent).getFolders();
while(childFolder.hasNext()) {
let child = childFolder.next();
Logger.log(child.getName());
readFilesInFolder(child)
getSubFolders(child);
}
return;
}
function listFolders() {
let parentFolder = DriveApp.getFolderById(drive_ID);
readFilesInFolder(parentFolder)
let childFolders = parentFolder.getFolders();
while(childFolders.hasNext()) {
let child = childFolders.next();
Logger.log(child.getName());
readFilesInFolder(child);
getSubFolders(child);
}
}
那接著我們執行看看——
補充的是,有人問說如果是在一進去 Google Drive 的根目錄(沒有 ID 的部分),要怎麼讀?其實就是直接 getFiles()
就行了。這邊是修改 官方範例的程式碼 供大家參考。
function readAllFiles(){
// Log the name of every file in the user's Drive.
let files = DriveApp.getFiles();
while (files.hasNext()) {
let file = files.next();
Logger.log(file.getName());
}
}
一樣按執行就好囉!好,那今天學了...
接著可以將結果參考 D8 寫入 Google Sheet。好,那今天就是我們的 D9,明天 D10 會繼續介紹結合讀取檔案後的操作模式。如果還有問題,透過留言之外,也可以到 Facebook Group,想開很久這次鐵人賽才真的開起來哈哈哈,歡迎來當 Founding Member。如果不想錯過可以訂閱按讚小鈴鐺(?),也歡迎留言跟我說你還想知道什麼做法/主題。我們明天見。